home *** CD-ROM | disk | FTP | other *** search
/ CICA 1995 August / CICA - The Ultimate Collection of Shareware for Windows (Disc 2) (August 1995).iso / disc2 / nt / source.exe / POSIX / ELVIS / OPTS.C < prev    next >
C/C++ Source or Header  |  1993-07-08  |  15KB  |  681 lines

  1. /* opts.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains the code that manages the run-time options -- The 
  12.  * values that can be modified via the "set" command.
  13.  */
  14.  
  15. #include "config.h"
  16. #include "vi.h"
  17. #ifndef NULL
  18. #define NULL (char *)0
  19. #endif
  20. extern char    *getenv();
  21.  
  22. /* maximum width to permit for strings, including ="" */
  23. #define MAXWIDTH 20
  24.  
  25. /* These are the default values of all options */
  26. char    o_autoindent[1] =    {FALSE};
  27. char    o_autoprint[1] =    {TRUE};
  28. char    o_autowrite[1] =     {FALSE};
  29. #ifndef NO_ERRLIST
  30. char    o_cc[30] =        {CC_COMMAND};
  31. #endif
  32. #ifndef NO_CHARATTR
  33. char    o_charattr[1] =        {FALSE};
  34. #endif
  35. char    o_columns[3] =        {80, 32, 255};
  36. #ifndef NO_DIGRAPH
  37. char    o_digraph[1] =        {FALSE};
  38. #endif
  39. char    o_directory[30] =    TMPDIR;
  40. char    o_edcompatible[1] =    {FALSE};
  41. char    o_errorbells[1] =    {TRUE};
  42. char    o_exrefresh[1] =    {TRUE};
  43. #ifndef NO_DIGRAPH
  44. char    o_flipcase[80]
  45. # if CS_IBMPC
  46.     = {"\207\200\201\232\202\220\204\216\206\217\221\222\224\231\244\245"}
  47. # endif
  48. # if CS_LATIN1
  49.     /* initialized by initopts() */
  50. # endif
  51.     ;
  52. #endif
  53. #ifndef NO_SENTENCE
  54. char    o_hideformat[1] =    {FALSE};
  55. #endif
  56. char    o_ignorecase[1] =    {FALSE};
  57. #ifndef NO_EXTENSIONS
  58. char    o_inputmode[1] =    {FALSE};
  59. #endif
  60. char    o_keytime[3] =        {2, 0, 5};
  61. char    o_keywordprg[80] =    {KEYWORDPRG};
  62. char    o_lines[3] =        {25, 2, 50};    /* More lines? Enlarge kbuf */
  63. char    o_list[1] =        {FALSE};
  64. #ifndef NO_MAGIC
  65. char    o_magic[1] =        {TRUE};
  66. #endif
  67. #ifndef NO_ERRLIST
  68. char    o_make[30] =        {MAKE_COMMAND};
  69. #endif
  70. #ifndef NO_MODELINE
  71. char    o_modeline[1] =        {FALSE};
  72. #endif
  73. #ifndef NO_SENTENCE
  74. char    o_paragraphs[30] =    "PPppIPLPQP";
  75. #endif
  76. #if MSDOS
  77. char    o_pcbios[1] =        {TRUE};
  78. #endif
  79. char    o_readonly[1] =        {FALSE};
  80. char    o_report[3] =        {5, 1, 127};
  81. char    o_scroll[3] =        {12, 1, 127};
  82. #ifndef NO_SENTENCE
  83. char    o_sections[30] =    "NHSHSSSEse";
  84. #endif
  85. char    o_shell[60] =        SHELL;
  86. char    o_shiftwidth[3] =    {8, 1, 255};
  87. #ifndef NO_SHOWMATCH
  88. char    o_showmatch[1] =    {FALSE};
  89. #endif
  90. #ifndef    NO_SHOWMODE
  91. char    o_smd[1] =        {FALSE};
  92. #endif
  93. char    o_sidescroll[3] =    {8, 1, 40};
  94. char    o_sync[1] =        {NEEDSYNC};
  95. char    o_tabstop[3] =        {8, 1, 40};
  96. char    o_term[30] =        "?";
  97. char    o_vbell[1] =        {TRUE};
  98. char    o_warn[1] =        {TRUE};
  99. char    o_wrapmargin[3] =    {0, 0, 255};
  100. char    o_wrapscan[1] =        {TRUE};
  101.  
  102.  
  103. /* The following describes the names & types of all options */
  104. #define BOOL    0
  105. #define    NUM    1
  106. #define    STR    2
  107. #define SET    0x01    /* this option has had its value altered */
  108. #define CANSET    0x02    /* this option can be set at any time */
  109. #define RCSET    0x06    /* this option can be set in a .exrc file only */
  110. #define MR    0x40    /* does this option affect the way text is displayed? */
  111. struct
  112. {
  113.     char    *name;    /* name of an option */
  114.     char    *nm;    /* short name of an option */
  115.     char    type;    /* type of an option */
  116.     char    flags;    /* boolean: has this option been set? */
  117.     char    *value;    /* value */
  118. }
  119.     opts[] =
  120. {
  121.     /* name            type    flags    redraw    value */
  122.     { "autoindent",    "ai",    BOOL,    CANSET    ,    o_autoindent    },
  123.     { "autoprint",    "ap",    BOOL,    CANSET    ,    o_autoprint    },
  124.     { "autowrite",    "aw",    BOOL,    CANSET    ,    o_autowrite    },
  125. #ifndef NO_ERRLIST
  126.     { "cc",        "cc",    STR,    CANSET    ,    o_cc        },
  127. #endif
  128. #ifndef NO_CHARATTR
  129.     { "charattr",    "ca",    BOOL,    CANSET    | MR,    o_charattr    },
  130. #endif
  131.     { "columns",    "co",    NUM,    SET    ,    o_columns    },
  132. #ifndef NO_DIGRAPH
  133.     { "digraph",    "dig",    BOOL,    CANSET    ,    o_digraph    },
  134. #endif
  135.     { "directory",    "dir",    STR,    RCSET    ,    o_directory    },
  136.     { "edcompatible","ed",    BOOL,    CANSET    ,    o_edcompatible    },
  137.     { "errorbells",    "eb",    BOOL,    CANSET    ,    o_errorbells    },
  138.     { "exrefresh",    "er",    BOOL,    CANSET    ,    o_exrefresh    },
  139. #ifndef NO_DIGRAPH
  140.     { "flipcase",    "fc",    STR,    CANSET    ,    o_flipcase    },
  141. #endif
  142. #ifndef NO_SENTENCE
  143.     { "hideformat",    "hf",    BOOL,    CANSET    | MR,    o_hideformat    },
  144. #endif
  145.     { "ignorecase",    "ic",    BOOL,    CANSET    ,    o_ignorecase    },
  146. #ifndef NO_EXTENSIONS
  147.     { "inputmode",    "im",    BOOL,    CANSET    ,    o_inputmode    },
  148. #endif
  149.     { "keytime",    "kt",    NUM,    CANSET    ,    o_keytime    },
  150.     { "keywordprg",    "kp",    STR,    CANSET    ,    o_keywordprg    },
  151.     { "lines",    "ls",    NUM,    SET    ,    o_lines        },
  152.     { "list",    "li",    BOOL,    CANSET    | MR,    o_list        },
  153. #ifndef NO_MAGIC
  154.     { "magic",    "ma",    BOOL,    CANSET    ,    o_magic        },
  155. #endif
  156. #ifndef NO_ERRLIST
  157.     { "make",    "mk",    STR,    CANSET    ,    o_make        },
  158. #endif
  159. #ifndef NO_MODELINE
  160.     { "modeline",    "ml",    BOOL,    CANSET    ,    o_modeline    },
  161. #endif
  162. #ifndef NO_SENTENCE
  163.     { "paragraphs",    "pa",    STR,    CANSET    ,    o_paragraphs    },
  164. #endif
  165. #if MSDOS
  166.     { "pcbios",    "pc",    BOOL,    SET    ,    o_pcbios    },
  167. #endif
  168.     { "readonly",    "ro",    BOOL,    CANSET    ,    o_readonly    },
  169.     { "report",    "re",    NUM,    CANSET    ,    o_report    },
  170.     { "scroll",    "sc",    NUM,    CANSET    ,    o_scroll    },
  171. #ifndef NO_SENTENCE
  172.     { "sections",    "se",    STR,    CANSET    ,    o_sections    },
  173. #endif
  174.     { "shell",    "sh",    STR,    CANSET    ,    o_shell        },
  175. #ifndef NO_SHOWMATCH
  176.     { "showmatch",    "sm",    BOOL,    CANSET    ,    o_showmatch    },
  177. #endif
  178. #ifndef    NO_SHOWMODE
  179.     { "showmode",    "smd",    BOOL,    CANSET    ,    o_smd        },
  180. #endif
  181.     { "shiftwidth",    "sw",    NUM,    CANSET    ,    o_shiftwidth    },
  182.     { "sidescroll",    "ss",    NUM,    CANSET    ,    o_sidescroll    },
  183.     { "sync",    "sy",    BOOL,    CANSET    ,    o_sync        },
  184.     { "tabstop",    "ts",    NUM,    CANSET    | MR,    o_tabstop    },
  185.     { "term",    "te",    STR,    SET    ,    o_term        },
  186.     { "vbell",    "vb",    BOOL,    CANSET    ,    o_vbell        },
  187.     { "warn",    "wa",    BOOL,    CANSET    ,    o_warn        },
  188.     { "wrapmargin",    "wm",    NUM,    CANSET    ,    o_wrapmargin    },
  189.     { "wrapscan",    "ws",    BOOL,    CANSET    ,    o_wrapscan    },
  190.     { NULL, NULL, 0, CANSET, NULL }
  191. };
  192.  
  193.  
  194. /* This function initializes certain options from environment variables, etc. */
  195. void initopts()
  196. {
  197.     char    *val;
  198.     int    i;
  199.  
  200.     /* set some stuff from environment variables */
  201. #if MSDOS
  202.     if (val = getenv("COMSPEC")) /* yes, ASSIGNMENT! */
  203. #else
  204.     if (val = getenv("SHELL")) /* yes, ASSIGNMENT! */
  205. #endif
  206.     {
  207.         strcpy(o_shell, val);
  208.     }
  209.  
  210. #if ANY_UNIX || DF_POSIX
  211.     if (val = getenv("TERM")) /* yes, ASSIGNMENT! */
  212.     {
  213.         strcpy(o_term, val);
  214.     }
  215. #endif
  216. #if TOS
  217.     val = "vt52";
  218.     strcpy(o_term, val);
  219. #endif
  220. #if MSDOS
  221.     if ((val = getenv("TERM")) /* yes, ASSIGNMENT! */
  222.         && strcmp(val, "pcbios"))
  223.     {
  224.         strcpy(o_term, val);
  225.         o_pcbios[0] = 0;
  226.     }
  227.     else
  228.     {
  229.         strcpy(o_term, "pcbios");
  230.         o_pcbios[0] = 1;
  231.     }
  232. #endif
  233. #if MSDOS || TOS || WIN_NT
  234.     if ((val = getenv("TMP")) /* yes, ASSIGNMENT! */
  235.     ||  (val = getenv("TEMP")))
  236.         strcpy(o_directory, val);
  237. #endif
  238.  
  239.     *o_scroll = LINES / 2 - 1;
  240.  
  241.     /* disable the vbell option if we don't know how to do a vbell */
  242.     if (!has_VB)
  243.     {
  244.         for (i = 0; opts[i].value != o_vbell; i++)
  245.         {
  246.         }
  247.         opts[i].flags &= ~CANSET;
  248.         *o_vbell = FALSE;
  249.     }
  250.  
  251. #ifndef NO_DIGRAPH
  252. # ifdef CS_LATIN1
  253.     for (i = 0, val = o_flipcase; i < 32; i++)
  254.     {
  255.         /* leave out the multiply/divide symbols */
  256.         if (i == 23)
  257.             continue;
  258.  
  259.         /* add upper/lowercase pair */
  260.         *val++ = i + 0xc0;
  261.         *val++ = i + 0xe0;
  262.     }
  263.     *val = '\0';
  264. # endif /* CS_LATIN1 */
  265. #endif /* not NO_DIGRAPH */
  266. }
  267.  
  268. /* This function lists the current values of all options */
  269. void dumpopts(all)
  270.     int    all;    /* boolean: dump all options, or just set ones? */
  271. {
  272. #ifndef NO_OPTCOLS
  273.     int    i, j, k;
  274.     char    nbuf[4];    /* used for converting numbers to ASCII */
  275.     int    widths[5];    /* width of each column, including gap */
  276.     int    ncols;        /* number of columns */
  277.     int    nrows;        /* number of options per column */
  278.     int    nset;        /* number of options to be output */
  279.     int    width;        /* width of a particular option */
  280.     int    todump[50];    /* indicies of options to be dumped */
  281.  
  282.     /* step 1: count the number of set options */
  283.     for (nset = i = 0; opts[i].name; i++)
  284.     {
  285.         if (all || (opts[i].flags & SET))
  286.         {
  287.             todump[nset++] = i;
  288.         }
  289.     }
  290.  
  291.     /* step two: try to use as many columns as possible */
  292.     for (ncols = (nset > 5 ? 5 : nset); ncols > 1; ncols--)
  293.     {
  294.         /* how many would go in this column? */
  295.         nrows = (nset + ncols - 1) / ncols;
  296.  
  297.         /* figure out the width of each column */
  298.         for (i = 0; i < ncols; i++)
  299.         {
  300.             widths[i] = 0;
  301.             for (j = 0, k = nrows * i; j < nrows && k < nset; j++, k++)
  302.             {
  303.                 /* figure out the width of a particular option */
  304.                 switch (opts[todump[k]].type)
  305.                 {
  306.                   case BOOL:
  307.                     if (!*opts[todump[k]].value)
  308.                         width = 2;
  309.                     else
  310.                         width = 0;
  311.                     break;
  312.  
  313.                   case STR:
  314.                     width = 3 + strlen(opts[todump[k]].value);
  315.                     if (width > MAXWIDTH)
  316.                         width = MAXWIDTH;
  317.                     break;
  318.  
  319.                   case NUM:
  320.                     width = 4;
  321.                     break;
  322.                 }
  323.                 width += strlen(opts[todump[k]].name);
  324.  
  325.                 /* if this is the widest so far, widen col */
  326.                 if (width > widths[i])
  327.                 {
  328.                     widths[i] = width;
  329.                 }
  330.             }
  331.  
  332.         }
  333.  
  334.         /* if the total width is narrow enough, then use it */
  335.         for (width = -2, i = 0; i < ncols; i++)
  336.         {
  337.             width += widths[i] + 2;
  338.         }
  339.         if (width < COLS - 1)
  340.         {
  341.             break;
  342.         }
  343.     }
  344.  
  345.     /* step 3: output the columns */
  346.     nrows = (nset + ncols - 1) / ncols;
  347.     for (i = 0; i < nrows; i++)
  348.     {
  349.         for (j = 0; j < ncols; j++)
  350.         {
  351.             /* if we hit the end of the options, quit */
  352.             k = i + j * nrows;
  353.             if (k >= nset)
  354.             {
  355.                 break;
  356.             }
  357.  
  358.             /* output this option's value */
  359.             width = 0;
  360.             switch (opts[todump[k]].type)
  361.             {
  362.               case BOOL:
  363.                 if (!*opts[todump[k]].value)
  364.                 {
  365.                     qaddch('n');
  366.                     qaddch('o');
  367.                     width = 2;
  368.                 }
  369.                 qaddstr(opts[todump[k]].name);
  370.                 width += strlen(opts[todump[k]].name);
  371.                 break;
  372.  
  373.               case NUM:
  374.                 sprintf(nbuf, "%-3d", UCHAR(*opts[todump[k]].value));
  375.                 qaddstr(opts[todump[k]].name);
  376.                 qaddch('=');
  377.                 qaddstr(nbuf);
  378.                 width = 4 + strlen(opts[todump[k]].name);
  379.                 break;
  380.  
  381.               case STR:
  382.                 qaddstr(opts[todump[k]].name);
  383.                 qaddch('=');
  384.                 qaddch('"');
  385.                 strcpy(tmpblk.c, opts[todump[k]].value);
  386.                 width = 3 + strlen(tmpblk.c);
  387.                 if (width > MAXWIDTH)
  388.                 {
  389.                     width = MAXWIDTH;
  390.                     strcpy(tmpblk.c + MAXWIDTH - 6, "...");
  391.                 }
  392.                 qaddstr(tmpblk.c);
  393.                 qaddch('"');
  394.                 width += strlen(opts[todump[k]].name);
  395.                 break;
  396.             }
  397.  
  398.             /* pad the field to the correct size */
  399.             if (k + nrows <= nset)
  400.             {
  401.                 while (width < widths[j] + 2)
  402.                 {
  403.                     qaddch(' ');
  404.                     width++;
  405.                 }
  406.             }
  407.         }
  408.         addch('\n');
  409.         exrefresh();
  410.     }
  411. #else
  412.     int    i;
  413.     int    col;
  414.     char    nbuf[4];
  415.  
  416.     for (i = col = 0; opts[i].name; i++)
  417.     {
  418.         /* if not set and not all, ignore this option */
  419.         if (!all && !(opts[i].flags & SET))
  420.         {
  421.             continue;
  422.         }
  423.  
  424.         /* align this option in one of the columns */
  425.         if (col > 52)
  426.         {
  427.             addch('\n');
  428.             col = 0;
  429.         }
  430.         else if (col > 26)
  431.         {
  432.             while (col < 52)
  433.             {
  434.                 qaddch(' ');
  435.                 col++;
  436.             }
  437.         }
  438.         else if (col > 0)
  439.         {
  440.             while (col < 26)
  441.             {
  442.                 qaddch(' ');
  443.                 col++;
  444.             }
  445.         }
  446.  
  447.         switch (opts[i].type)
  448.         {
  449.           case BOOL:
  450.             if (!*opts[i].value)
  451.             {
  452.                 qaddch('n');
  453.                 qaddch('o');
  454.                 col += 2;
  455.             }
  456.             qaddstr(opts[i].name);
  457.             col += strlen(opts[i].name);
  458.             break;
  459.  
  460.           case NUM:
  461.             sprintf(nbuf, "%-3d", UCHAR(*opts[i].value));
  462.             qaddstr(opts[i].name);
  463.             qaddch('=');
  464.             qaddstr(nbuf);
  465.             col += 4 + strlen(opts[i].name);
  466.             break;
  467.  
  468.           case STR:
  469.             qaddstr(opts[i].name);
  470.             qaddch('=');
  471.             qaddch('"');
  472.             qaddstr(opts[i].value);
  473.             qaddch('"');
  474.             col += 3 + strlen(opts[i].name) + strlen(opts[i].value);
  475.             break;
  476.         }
  477.         exrefresh();
  478.     }
  479.     if (col > 0)
  480.     {
  481.         addch('\n');
  482.         exrefresh();
  483.     }
  484. #endif
  485. }
  486.  
  487. #ifndef NO_MKEXRC
  488. /* This function saves the current configuarion of options to a file */
  489. void saveopts(fd)
  490.     int    fd;    /* file descriptor to write to */
  491. {
  492.     int    i;
  493.     char    buf[256], *pos;
  494.  
  495.     /* write each set options */
  496.     for (i = 0; opts[i].name; i++)
  497.     {
  498.         /* if unset or unsettable, ignore this option */
  499.         if (!(opts[i].flags & SET) || !(opts[i].flags & CANSET))
  500.         {
  501.             continue;
  502.         }
  503.  
  504.         strcpy(buf, "set ");
  505.         pos = &buf[4];
  506.         switch (opts[i].type)
  507.         {
  508.           case BOOL:
  509.             if (!*opts[i].value)
  510.             {
  511.                 *pos++='n';
  512.                 *pos++='o';
  513.             }
  514.             strcpy(pos, opts[i].name);
  515.             strcat(pos, "\n");
  516.             break;
  517.  
  518.           case NUM:
  519.             sprintf(pos, "%s=%-3d\n", opts[i].name, *opts[i].value & 0xff);
  520.             break;
  521.  
  522.           case STR:
  523.             sprintf(pos, "%s=\"%s\"\n", opts[i].name, opts[i].value);
  524.             break;
  525.         }
  526.         twrite(fd, buf, strlen(buf));
  527.     }
  528. }
  529. #endif
  530.  
  531.  
  532. /* This function changes the values of one or more options. */
  533. void setopts(assignments)
  534.     char    *assignments;    /* a string containing option assignments */
  535. {
  536.     char    *name;        /* name of variable in assignments */
  537.     char    *value;        /* value of the variable */
  538.     char    *scan;        /* used for moving through strings */
  539.     int    i, j;
  540.  
  541.     /* for each assignment... */
  542.     for (name = assignments; *name; )
  543.     {
  544.         /* skip whitespace */
  545.         if (*name == ' ' || *name == '\t')
  546.         {
  547.             name++;
  548.             continue;
  549.         }
  550.  
  551.         /* find the value, if any */
  552.         for (scan = name; *scan >= 'a' && *scan <= 'z'; scan++)
  553.         {
  554.         }
  555.         if (*scan == '=')
  556.         {
  557.             *scan++ = '\0';
  558.             if (*scan == '"')
  559.             {
  560.                 value = ++scan;
  561.                 while (*scan && *scan != '"')
  562.                 {
  563.                     scan++;
  564.                 }
  565.                 if (*scan)
  566.                 {
  567.                     *scan++ = '\0';
  568.                 }
  569.             }
  570.             else
  571.             {
  572.                 value = scan;
  573.                 while (*scan && *scan != ' ' && *scan != '\t')
  574.                 {
  575.                     scan++;
  576.                 }
  577.                 if (*scan)
  578.                 {
  579.                     *scan++ = '\0';
  580.                 }
  581.             }
  582.         }
  583.         else
  584.         {
  585.             if (*scan)
  586.             {
  587.                 *scan++ = '\0';
  588.             }
  589.             value = NULL;
  590.             if (name[0] == 'n' && name[1] == 'o')
  591.             {
  592.                 name += 2;
  593.             }
  594.         }
  595.  
  596.         /* find the variable */
  597.         for (i = 0;
  598.              opts[i].name && strcmp(opts[i].name, name) && strcmp(opts[i].nm, name);
  599.              i++)
  600.         {
  601.         }
  602.  
  603.         /* change the variable */
  604.         if (!opts[i].name)
  605.         {
  606.             msg("invalid option name \"%s\"", name);
  607.         }
  608.         else if ((opts[i].flags & CANSET) != CANSET)
  609.         {
  610.             msg("option \"%s\" can't be altered", name);
  611.         }
  612.         else if ((opts[i].flags & RCSET) != CANSET && nlines >= 1L)
  613.         {
  614.             msg("option \"%s\" can only be set in a %s file", name, EXRC);
  615.         }
  616.         else if (value)
  617.         {
  618.             switch (opts[i].type)
  619.             {
  620.               case BOOL:
  621.                 msg("option \"[no]%s\" is boolean", name);
  622.                 break;
  623.  
  624.               case NUM:
  625.                 j = atoi(value);
  626.                 if (j == 0 && *value != '0')
  627.                 {
  628.                     msg("option \"%s\" must have a numeric value", name);
  629.                 }
  630.                 else if (j < opts[i].value[1] || j > (opts[i].value[2] & 0xff))
  631.                 {
  632.                     msg("option \"%s\" must have a value between %d and %d",
  633.                         name, opts[i].value[1], opts[i].value[2] & 0xff);
  634.                 }
  635.                 else
  636.                 {
  637.                     *opts[i].value = atoi(value);
  638.                     opts[i].flags |= SET;
  639.                 }
  640.                 break;
  641.  
  642.               case STR:
  643.                 strcpy(opts[i].value, value);
  644.                 opts[i].flags |= SET;
  645.                 break;
  646.             }
  647.             if (opts[i].flags & MR)
  648.             {
  649.                 mustredraw = TRUE;
  650.             }
  651.         }
  652.         else /* valid option, no value */
  653.         {
  654.             if (opts[i].type == BOOL)
  655.             {
  656.                 *opts[i].value = (name[-1] != 'o');
  657.                 opts[i].flags |= SET;
  658.                 if (opts[i].flags & MR)
  659.                 {
  660.                     mustredraw = TRUE;
  661.                 }
  662.             }
  663.             else
  664.             {
  665.                 msg("option \"%s\" must be given a value", name);
  666.             }
  667.         }
  668.  
  669.         /* move on to the next option */
  670.         name = scan;
  671.     }
  672.  
  673.     /* special processing ... */
  674.  
  675.     /* if "readonly" then set the READONLY flag for this file */
  676.     if (*o_readonly)
  677.     {
  678.         setflag(file, READONLY);
  679.     }
  680. }
  681.